﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Av.Utils;

namespace JrGreenMonster
{

    public class IttcWorkerConfiguration
    {
        protected string m_ittcHostname = Settings.IttcHostname;
        protected int m_ittcPort = Settings.IttcPort;

        #region " ITTC server URL config "
        public string IttcHostname
        {
            get
            {
                return m_ittcHostname;
            }
            set
            {
                m_ittcHostname = value;
            }
        }

        public int IttcPort
        {
            get
            {
                return m_ittcPort;
            }
            set
            {
                m_ittcPort = value;
            }
        }

        public string IttcUrl { get; set; }

        #endregion    }

        #region " CST signals config "

        /// <summary>
        /// URL to POST CST signals file
        /// </summary>
        public string CstSignalsUploadUrl { get; set; }

        /// <summary>
        /// CST signals file to upload
        /// </summary>
        public string CstSignalsFilename { get; set; }

        /// <summary>
        /// Gets/sets delay between CST singals upload
        /// </summary>
        public int CstSignalsUploadDelayS { get; set; }
        
        #endregion
    }

    public class IttcWorkerThread
    {
        public const int ExitEvent = 0;
        //public const int CstSignalsEvent = 1;

        protected IttcWorkerConfiguration m_config = null;

        /// <summary>
        /// Helper to watch when tasks should be run
        /// </summary>
        protected TimeDelayWatcher m_delayWatcher = new TimeDelayWatcher();

        /// <summary>
        /// Main thread
        /// </summary>
        protected Thread m_thread = null;

        /// <summary>
        /// Signals main thread to stop
        /// </summary>
        protected WaitHandle[] m_arEvents = null;

        /// <summary>
        /// Fires when some new information is available
        /// </summary>
        public event MyNotificationDelegate StatusChanged = null;

        /// <summary>
        /// Gets/sets whether thread is running
        /// </summary>
        public bool IsRunning { get; set; }

        public void Start(IttcWorkerConfiguration config)
        {
            //m_delayBetweenRunsMs[CstSignalsEvent] = cstSignalsDelayMs;
            //Log4cs.Log("Starting ITTC thread. CST signals upload delay is {0}ms...", m_delayBetweenRunsMs[CstSignalsEvent]);
            if( IsRunning )
            {
                Log4cs.Log(Importance.Error, "Attempting to start already running ITTC thread!");
                throw new Exception("ITTC thread is already running!");
            }

            m_config = config;
            m_delayWatcher.SetDelayBetweenRunsMs(TimeDelayWatcher.TaskId.CstSignalUpload, config.CstSignalsUploadDelayS);
            if( StatusChanged != null )
            {
                StatusChanged("IttcWorkerThread", new MyNotificationEventArgs() { Text = string.Format("CST signals file {0} will be uploaded every {0}s", config.CstSignalsFilename, config.CstSignalsUploadDelayS) });
            }

            m_thread = new Thread(new ParameterizedThreadStart(Run));
            IsRunning = true;
            m_arEvents = new WaitHandle[1];
            m_arEvents[ExitEvent] = new ManualResetEvent(false);
            //m_arEvents[CstSignalsEvent] = new ManualResetEvent(false);
            m_thread.Start(config);
        }


        protected void Run(object obj)
        {
            Log4cs.Log("Entering running thread...");

            IttcWorkerConfiguration config = (IttcWorkerConfiguration)obj;
            IttcWebClient wc = new IttcWebClient();
            string resp = "";

            //EventWaitHandle[] m_events = new ManualResetEvent[1];
            //m_events[0] = new ManualResetEvent(false);
            while( IsRunning )
            {
                try
                {
                    //Log4cs.Log(Importance.Debug, "Still waiting...");
                    switch(WaitHandle.WaitAny(m_arEvents, 500))
                    {
                        case ExitEvent:
                            Log4cs.Log("Got exit signal. Stopping ITTC worker thread.");
                            IsRunning = false;
                            break;
                        default:
                            //Log4cs.Log("Next CST upload in {0} s", m_delayWatcher.GetSecondsTillNextRun(TimeDelayWatcher.TaskId.CstSignalUpload));
                            if(m_delayWatcher.GetSecondsTillNextRun(TimeDelayWatcher.TaskId.CstSignalUpload) < 1)
                            {
                                Log4cs.Log("Time to upload CST signals to {0}...", config.CstSignalsUploadUrl);
                                if( StatusChanged != null )
                                {
                                    StatusChanged("IttcWorkerThread", new MyNotificationEventArgs() { Text = "Uploading CST signals..." });
                                }

                                wc = new IttcWebClient();
                                resp = wc.PostCstSignals(config.CstSignalsUploadUrl, config.CstSignalsFilename);
                                //Log4cs.Log("Got response from ITTC server: {0}", resp);
                                if(StatusChanged != null)
                                {
                                    StatusChanged("IttcWorkerThread", new MyNotificationEventArgs() { Text = resp });
                                }

                                m_delayWatcher.Touch(TimeDelayWatcher.TaskId.CstSignalUpload);
                            }
                            break;
                    }
                    //Log4cs.Log("Got event #{0}...", eventId);

                } catch(Exception ex)
                {
                    Log4cs.Log(Importance.Error, "Error running ITTC periodical task!");
                    Log4cs.Log(Importance.Debug, ex.ToString());
                }
            }

            Log4cs.Log("Exiting running thread...");
        }


        internal void Stop()
        {
            IsRunning = false;
            if( m_arEvents != null )
            {
                ((ManualResetEvent)m_arEvents[ExitEvent]).Set();
            }
        }

        protected int[] m_delayBetweenRunsMs = new int[] { 0, 120000 };
        protected DateTime[] m_lastRunAt = new DateTime[2];
        protected int TimeFromLastRunMs(int eventId)
        {
            //Log4cs.Log("Event #{0} last run at {1}", eventId, m_lastRunAt[eventId]);
            if( m_lastRunAt[eventId] == DateTime.MinValue )
            {
                return int.MaxValue;
            }
            return (int)((TimeSpan)(DateTime.Now - m_lastRunAt[eventId])).TotalMilliseconds;
        }

        protected void MarkRun(int eventId)
        {
            m_lastRunAt[eventId] = DateTime.Now;
        }
    }
}
